<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
  <meta name="theme-color" content="#222">
  <meta name="generator" content="Hexo 5.4.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

  <link rel="stylesheet" href="/css/main.css">



  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.2/css/all.min.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css">

  <script class="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {
      "hostname": "holidaypenguin.gitee.io",
      "root": "/",
      "images": "/images",
      "scheme": "Mist",
      "version": "8.2.2",
      "exturl": false,
      "sidebar": {
        "position": "right",
        "display": "always",
        "padding": 18,
        "offset": 12
      },
      "copycode": true,
      "bookmark": {
        "enable": false,
        "color": "#222",
        "save": "auto"
      },
      "fancybox": false,
      "mediumzoom": false,
      "lazyload": false,
      "pangu": false,
      "comments": {
        "style": "tabs",
        "active": null,
        "storage": true,
        "lazyload": false,
        "nav": null
      },
      "motion": {
        "enable": true,
        "async": true,
        "transition": {
          "post_block": "fadeIn",
          "post_header": "fadeInDown",
          "post_body": "fadeInDown",
          "coll_header": "fadeInLeft",
          "sidebar": "slideUpIn"
        }
      },
      "prism": false,
      "i18n": {
        "placeholder": "搜索...",
        "empty": "没有找到任何搜索结果：${query}",
        "hits_time": "找到 ${hits} 个搜索结果（用时 ${time} 毫秒）",
        "hits": "找到 ${hits} 个搜索结果"
      },
      "path": "/search.xml",
      "localsearch": {
        "enable": true,
        "trigger": "auto",
        "top_n_per_article": 1,
        "unescape": false,
        "preload": false
      }
    };
  </script>
  <meta property="og:type" content="article">
  <meta property="og:title" content="2020 前端技术发展回顾">
  <meta property="og:url" content="https://holidaypenguin.gitee.io/blob/2021-06-09-review-of-the-development-of-front-end-technology-in-2020/index.html">
  <meta property="og:site_name" content="HolidayPenguin">
  <meta property="og:locale" content="zh_CN">
  <meta property="og:image" content="https://visitor-badge.glitch.me/badge?page_id=holidaypenguin.gitee.io/">
  <meta property="article:published_time" content="2021-06-09T01:59:19.000Z">
  <meta property="article:modified_time" content="2021-06-09T01:59:19.000Z">
  <meta property="article:author" content="holidaypenguin">
  <meta property="article:tag" content="JavaScript">
  <meta property="article:tag" content="2020">
  <meta name="twitter:card" content="summary">
  <meta name="twitter:image" content="https://visitor-badge.glitch.me/badge?page_id=holidaypenguin.gitee.io/">


  <link rel="canonical" href="https://holidaypenguin.gitee.io/blob/2021-06-09-review-of-the-development-of-front-end-technology-in-2020/">


  <script class="page-configurations">
    // https://hexo.io/docs/variables.html
    CONFIG.page = {
      sidebar: "",
      isHome: false,
      isPost: true,
      lang: 'zh-CN'
    };
  </script>
  <title>2020 前端技术发展回顾 | HolidayPenguin</title>





  <noscript>
    <style>
      body {
        margin-top: 2rem;
      }

      .use-motion .menu-item,
      .use-motion .sidebar,
      .use-motion .post-block,
      .use-motion .pagination,
      .use-motion .comments,
      .use-motion .post-header,
      .use-motion .post-body,
      .use-motion .collection-header {
        visibility: visible;
      }

      .use-motion .header,
      .use-motion .site-brand-container .toggle,
      .use-motion .footer {
        opacity: initial;
      }

      .use-motion .site-title,
      .use-motion .site-subtitle,
      .use-motion .custom-logo-image {
        opacity: initial;
        top: initial;
      }

      .use-motion .logo-line {
        transform: scaleX(1);
      }

      .search-pop-overlay,
      .sidebar-nav {
        display: none;
      }

      .sidebar-panel {
        display: block;
      }
    </style>
  </noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner">
        <div class="site-brand-container">
          <div class="site-nav-toggle">
            <div class="toggle" aria-label="切换导航栏" role="button">
              <span class="toggle-line"></span>
              <span class="toggle-line"></span>
              <span class="toggle-line"></span>
            </div>
          </div>

          <div class="site-meta">

            <a href="/" class="brand" rel="start">
              <i class="logo-line"></i>
              <h1 class="site-title">HolidayPenguin</h1>
              <i class="logo-line"></i>
            </a>
          </div>

          <div class="site-nav-right">
            <div class="toggle popup-trigger">
              <i class="fa fa-search fa-fw fa-lg"></i>
            </div>
          </div>
        </div>



        <nav class="site-nav">
          <ul class="main-menu menu">
            <li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li>
            <li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li>
            <li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li>
            <li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
            <li class="menu-item menu-item-search">
              <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
              </a>
            </li>
          </ul>
        </nav>



        <div class="search-pop-overlay">
          <div class="popup search-popup">
            <div class="search-header">
              <span class="search-icon">
                <i class="fa fa-search"></i>
              </span>
              <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off" maxlength="80" placeholder="搜索..." spellcheck="false" type="search" class="search-input">
              </div>
              <span class="popup-btn-close" role="button">
                <i class="fa fa-times-circle"></i>
              </span>
            </div>
            <div class="search-result-container no-result">
              <div class="search-result-icon">
                <i class="fa fa-spinner fa-pulse fa-5x"></i>
              </div>
            </div>

          </div>
        </div>

      </div>


      <div class="toggle sidebar-toggle" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
      </div>

      <aside class="sidebar">

        <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
          <ul class="sidebar-nav">
            <li class="sidebar-nav-toc">
              文章目录
            </li>
            <li class="sidebar-nav-overview">
              站点概览
            </li>
          </ul>

          <div class="sidebar-panel-container">
            <!--noindex-->
            <div class="post-toc-wrap sidebar-panel">
              <div class="post-toc animated">
                <ol class="nav">
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A0%87%E5%87%86%E4%B8%8E%E5%8D%8F%E8%AE%AE-ECMAScript"><span class="nav-number">1.</span> <span class="nav-text">标准与协议 ECMAScript</span></a></li>
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#CSS-%E7%89%B9%E6%80%A7"><span class="nav-number">2.</span> <span class="nav-text">CSS 特性</span></a></li>
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8A%80%E6%9C%AF%E9%A2%86%E5%9F%9F"><span class="nav-number">3.</span> <span class="nav-text">技术领域</span></a></li>
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AB%AF%E6%8A%80%E6%9C%AF-WebAPI"><span class="nav-number">4.</span> <span class="nav-text">端技术 WebAPI</span></a></li>
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A1%86%E6%9E%B6%E5%92%8C%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-%E6%A1%86%E6%9E%B6"><span class="nav-number">5.</span> <span class="nav-text">框架和解决方案 框架</span></a></li>
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#Webpack-%E5%8F%88%E6%9C%89%E6%9B%B4%E5%A4%9A%E5%AF%B9%E6%89%8B"><span class="nav-number">6.</span> <span class="nav-text">Webpack 又有更多对手</span></a></li>
                  <li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%87%B4%E8%B0%A2"><span class="nav-number">7.</span> <span class="nav-text">致谢</span></a>
                    <ol class="nav-child">
                      <li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8B%98%E8%AF%AF"><span class="nav-number">7.1.</span> <span class="nav-text">勘误</span></a></li>
                    </ol>
                  </li>
                </ol>
              </div>
            </div>
            <!--/noindex-->

            <div class="site-overview-wrap sidebar-panel">
              <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
                <p class="site-author-name" itemprop="name">holidaypenguin</p>
                <div class="site-description" itemprop="description"></div>
              </div>
              <div class="site-state-wrap site-overview-item animated">
                <nav class="site-state">
                  <div class="site-state-item site-state-posts">
                    <a href="/archives/">

                      <span class="site-state-item-count">138</span>
                      <span class="site-state-item-name">日志</span>
                    </a>
                  </div>
                  <div class="site-state-item site-state-categories">
                    <a href="/categories/">

                      <span class="site-state-item-count">26</span>
                      <span class="site-state-item-name">分类</span></a>
                  </div>
                  <div class="site-state-item site-state-tags">
                    <a href="/tags/">

                      <span class="site-state-item-count">234</span>
                      <span class="site-state-item-name">标签</span></a>
                  </div>
                </nav>
              </div>
              <div class="links-of-author site-overview-item animated">
                <span class="links-of-author-item">
                  <a href="https://github.com/holidaypenguin" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;holidaypenguin" rel="noopener" target="_blank"><i class="github fa-fw"></i>GitHub</a>
                </span>
                <span class="links-of-author-item">
                  <a href="mailto:songshipeng2016@gmail.com" title="E-Mail → mailto:songshipeng2016@gmail.com" rel="noopener" target="_blank"><i class="envelope fa-fw"></i>E-Mail</a>
                </span>
              </div>



            </div>
          </div>
        </div>
      </aside>
      <div class="sidebar-dimmer"></div>


    </header>


    <div class="back-to-top" role="button">
      <i class="fa fa-arrow-up"></i>
      <span>0%</span>
    </div>

    <noscript>
      <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
    </noscript>


    <div class="main-inner post posts-expand">





      <div class="post-block">



        <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
          <link itemprop="mainEntityOfPage" href="https://holidaypenguin.gitee.io/blob/2021-06-09-review-of-the-development-of-front-end-technology-in-2020/">

          <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
            <meta itemprop="image" content="/images/avatar.gif">
            <meta itemprop="name" content="holidaypenguin">
            <meta itemprop="description" content="">
          </span>

          <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
            <meta itemprop="name" content="HolidayPenguin">
          </span>
          <header class="post-header">
            <h1 class="post-title" itemprop="name headline">
              2020 前端技术发展回顾
            </h1>

            <div class="post-meta-container">
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>

                  <time title="创建时间：2021-06-09 09:59:19" itemprop="dateCreated datePublished" datetime="2021-06-09T09:59:19+08:00">2021-06-09</time>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-folder"></i>
                  </span>
                  <span class="post-meta-item-text">分类于</span>
                  <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                    <a href="/categories/JavaScript/" itemprop="url" rel="index"><span itemprop="name">JavaScript</span></a>
                  </span>
                </span>


                <span id="/blob/2021-06-09-review-of-the-development-of-front-end-technology-in-2020/" class="post-meta-item leancloud_visitors" data-flag-title="2020 前端技术发展回顾" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
              </div>

              <div class="post-description">
                <!-- more -->
              </div>
            </div>
          </header>




          <div class="post-body" itemprop="articleBody">
            <p><a target="_blank" rel="noopener" href="https://github.com/jwenjian/visitor-count-badge"><img src="" data-original="https://visitor-badge.glitch.me/badge?page_id=holidaypenguin.gitee.io/" alt="总访客数量"></a></p>
            <p>本文系转载，原文地址：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/343552059">https://zhuanlan.zhihu.com/p/343552059</a></p>
            <p>2020 终究是一个不平凡的一年，我们经历了太多坎坷与磨炼。甚至受 COVID-19 疫情的影响，Chrome 浏览器罕见的断更了，Chrome 82 就此缺席。但 Web 生态依旧保持了欣欣向荣的活力，一大批新特性持续不断涌现出来。</p>
            <h2 id="标准与协议-ECMAScript"><a href="#标准与协议-ECMAScript" class="headerlink" title="标准与协议 ECMAScript"></a>标准与协议 ECMAScript</h2>
            <ul>
              <li>
                <p><a target="_blank" rel="noopener" href="https://www.ecma-international.org/ecma-262/11.0/index.html">ES2020 如期发布</a>，此前进入 Stage 4 的提案均被纳入正式规范。</p>
                <ul>
                  <li><code>import()</code>：用于动态加载模块；</li>
                  <li><code>import.meta</code>：一个对象，用来携带模块相关的元信息；</li>
                  <li><code>export * as newModule from &#39;package&#39;</code>：一种新的聚合导出语法；</li>
                  <li>新增<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining">可选链运算符</a><code>?.</code> ：能够在属性访问、方法调用前检查其是否存在；</li>
                  <li>新增<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator">空值合并操作符</a><code>??</code> ：用来提供默认值，说明上下文是 <code>null</code> 或 <code>undefined</code>；</li>
                  <li>新增 <code>BigInt</code> 基础数值类型：可以表示绝对值大于 <code>2^53-1</code> 的整数而无精度损失；</li>
                  <li>新增 <code>Promise.allSettled()</code>：返回一个在所有给定的 Promise 已进入 fullfilled 或 rejected 状态的 Promise，并带有一个对象数组，每个对象表示对应的 Promise 结果；</li>
                  <li>新增 <code>String.prototype.matchAll</code>：一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。与 <code>RegExp.prototype.exec</code> 的区别在于：如果要得到所有匹配项，需要正则表达式有 <code>/g</code> 标志，且多次调用 <code>.exec()</code> 才会得到所有匹配的结果，而 <code>matchAll</code> 只需要调用一次；</li>
                  <li>新增 <code>globalThis</code>：用来解决浏览器、Node.js 等不同环境下，全局对象名称不统一，获取全局对象比较麻烦的问题。</li>
                </ul>
              </li>
            </ul>
            <h2 id="CSS-特性"><a href="#CSS-特性" class="headerlink" title="CSS 特性"></a>CSS 特性</h2>
            <ul>
              <li><a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout">Flexbox</a> 已经全面普及，垂直居中不再是前端「打工人」的烦恼丝。双飞翼、圣杯布局等各种 Hack 的手法也终究淹没在历史的长河之中。</li>
              <li>Flexbox 中也支持了 <code>gap</code> 属性，可以非常方便的调节相邻元素的间距，<a target="_blank" rel="noopener" href="https://caniuse.com/flexbox-gap">主流浏览器均已支持</a>；</li>
              <li>所有主流浏览器都支持了 <a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout">CSS Grid</a>，同时也被更多人熟知和使用，<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Subgrid">Subgrid</a>（子网格）在 <a target="_blank" rel="noopener" href="https://caniuse.com/css-subgrid">Firefox 71</a> 中<a target="_blank" rel="noopener" href="https://hacks.mozilla.org/2019/06/css-grid-level-2-subgrid-is-coming-to-firefox/">正式发布</a>。Float、inline-block 不再成为页面布局首选，CSS 布局正在从一维向二维迈进；</li>
              <li>纵横比属性 <code>aspect-ratio</code> 已经在 <a target="_blank" rel="noopener" href="https://www.chromestatus.com/feature/5738050678161408">Chrome 88 中支持</a>，通过它可以非常方便的实现元素的等比缩放；</li>
              <li>Firefox 创新性的基于 <a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout">CSS Grid 实现了瀑布流布局</a>（<code>grid-template-rows: masonry</code>），并推动其<a target="_blank" rel="noopener" href="https://drafts.csswg.org/css-grid-3/#masonry-layout">进入规范</a>，这将比 JavaScript 方案拥有更好的性能；</li>
              <li>容器查询（Container Queries）取得了实质性进展，<a target="_blank" rel="noopener" href="https://groups.google.com/a/chromium.org/g/blink-dev/c/u1AKdrXhPGI/m/wrJb-unhAgAJ">Chrome 正在快马加鞭的实现中</a>。有了它响应式组件如虎添翼，可以根据容器大小来设置不同的样式；</li>
              <li>Chrome 86 和 Firefox 85 支持了 <code>:focus-visible</code> 伪类，可以单独控制键盘的焦点样式，请停止使用<code>* &#123; outline: none; &#125;</code>，改用 <code>:focus:not(:focus-visible) &#123; outline: none; &#125; :focus-visible &#123; outline: auto; &#125;</code>，这样既可以保证鼠标点击时没有焦点框，也保留了键盘 Tab 键操作的时候出现焦点框，使页面的无障碍性更加友好。</li>
            </ul>
            <h2 id="技术领域"><a href="#技术领域" class="headerlink" title="技术领域"></a>技术领域</h2>
            <blockquote>
              <p>数据来自 <a target="_blank" rel="noopener" href="https://2020.stateofcss.com/en-US/">The State of CSS 2020</a></p>
            </blockquote>
            <ul>
              <li>处理器：三大预处理器（<a target="_blank" rel="noopener" href="https://sass-lang.com/">Sass</a>、<a target="_blank" rel="noopener" href="https://lesscss.org/">Less</a>、<a target="_blank" rel="noopener" href="https://stylus-lang.com/">Stylus</a>）中，Sass 满意度最高，其他两者相对较低，其中很大一部分人转投了后处理器 <a target="_blank" rel="noopener" href="https://postcss.org/">PostCSS</a> 的阵营。 Sass 社区的 <a target="_blank" rel="noopener" href="https://sass-lang.com/blog/libsass-is-deprecated">LibSass 宣布已弃用</a>，不再支持新的功能的开发，LibSass 和 <a target="_blank" rel="noopener" href="https://github.com/sass/node-sass">node-sass</a> 将在最大努力的基础上继续无限期维护，包括修复主要的错误和安全性问题，并保持与最新版本的 Node.js 相兼容；</li>
              <li>CSS 框架层面：前有 CSS-in-JS 的持续追击，后有以「实用原子类」为代表的 <a target="_blank" rel="noopener" href="https://tailwindcss.com/">Tailwind CSS</a> 异军突起，迫使我们重新思考 CSS 语义化类名的真谛。传统 CSS 框架中，用户继续使用 <a target="_blank" rel="noopener" href="https://getbootstrap.com/docs/3.4/css/">Bootstrap</a> 的意愿明显下降，<a target="_blank" rel="noopener" href="https://purecss.io/">Pure.CSS</a> 欢迎度不减；</li>
              <li>CSS-in-JS：<a target="_blank" rel="noopener" href="https://github.com/css-modules/css-modules">CSS Modules</a> 和 <a target="_blank" rel="noopener" href="https://www.styled-components.com/">Styled Components</a> 继续保持在第一阵营；</li>
              <li>Linter：<a target="_blank" rel="noopener" href="https://stylelint.io/">Stylelint</a> 依然是 Style Lint 领域的领头羊。<a target="_blank" rel="noopener" href="https://prettier.io/">Prettier</a> 作为「全能」的格式化工具，支持原生 CSS、 SCSS、Less 三种语法，是开发者格式化样式的不二之选，<a target="_blank" rel="noopener" href="https://prettier.io/docs/en/precommit.html">搭配 Git Hooks</a> 使用，妙不可言。</li>
            </ul>
            <h2 id="端技术-WebAPI"><a href="#端技术-WebAPI" class="headerlink" title="端技术 WebAPI"></a>端技术 WebAPI</h2>
            <ul>
              <li>Chrome 87 开始，可以在<a target="_blank" rel="noopener" href="https://web.dev/camera-pan-tilt-zoom/"> JavaScript 层面控制摄像头的平移、倾斜和缩放了</a>；</li>
              <li><a target="_blank" rel="noopener" href="https://developers.chrome.com/origintrials/#/view_trial/236438980436951041">Web NFC</a> 在 Chrome 81 开始进入初始试用计划；</li>
              <li><a target="_blank" rel="noopener" href="https://webkit.org/blog/11340/new-webkit-features-in-safari-14/">Safari 14</a> 已支持 WebP 图片格式，至此，四大主流浏览器（Chrome、Firefox、Edge、Safari）已全部支持 WebP；</li>
              <li><a target="_blank" rel="noopener" href="https://webkit.org/blog/11340/new-webkit-features-in-safari-14/">Safari 14</a> 已支持 Web 端通过 <a target="_blank" rel="noopener" href="https://www.w3.org/TR/webauthn-1/">Web Authentication API</a> 调用 Face ID 和 Touch ID 验证用户；</li>
              <li>优化高 DOM 渲染压力场景的 <a target="_blank" rel="noopener" href="https://github.com/WICG/display-locking">Display Locking</a> （展现锁定）提案再次更新；</li>
              <li>下一代图片格式 <a target="_blank" rel="noopener" href="https://netflixtechblog.com/avif-for-next-generation-image-coding-b1d75675fe4">AVIF</a>（AV1 Image File Format）已经来了，此格式比 JPEG 小 50% 左右、比 WebP 小 20% 左右，相关性能跑分<a target="_blank" rel="noopener" href="https://netflixtechblog.com/avif-for-next-generation-image-coding-b1d75675fe4">见此</a>，目前 <a target="_blank" rel="noopener" href="https://developers.google.com/web/updates/2020/08/nic85">Chrome 85</a>、<a target="_blank" rel="noopener" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1625363">Firefox 77</a> 已支持；</li>
              <li>HTML <a target="_blank" rel="noopener" href="https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-enterkeyhint-attribute">enterkeyhint 属性</a>已在 Chrome 77、Safari 13.1 得到支持（Firefox 支持私有的 <a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-mozactionhint">mozactionhint</a> 属性），该属性可以使移动设备键盘中的 enter 键根据情景展现为不同的文案和样式；</li>
              <li>W3C 沉浸式 Web 工作组发布 <a target="_blank" rel="noopener" href="https://www.w3.org/TR/2020/WD-webxr-hand-input-1-20201022/">WebXR 手势输入模块 Level 1 规范</a> 的首个公开工作草案，该模块具有追踪关节手势的功能，可用于在 VR 场景中识别手部关节姿势或渲染手势模型。</li>
            </ul>
            <p>安全隐私保护得到完善</p>
            <p>2020 年是欧盟通用数据保护协议 GDPR 强制生效的第三年，也是<a target="_blank" rel="noopener" href="https://blog.google/topics/google-cloud/answering-your-questions-about-meltdown-and-spectre/">熔断 Meltdown 与幽灵 Spectre</a> 漏洞发生的第三年。在 2020 年，各大浏览器安全和隐私保护策略得到了很大的进展。</p>
            <ul>
              <li>
                <p>下线有安全隐患的支持：</p>
              </li>
              <li>
                <ul>
                  <li>TLS 1.0 &amp; TLS 1.1 已在 <a target="_blank" rel="noopener" href="https://developers.google.com/web/updates/2020/05/chrome-84-deps-rems">Chrome 84+</a>、<a target="_blank" rel="noopener" href="https://hacks.mozilla.org/2020/03/security-means-more-with-firefox-74-2/">Firefox 74+</a>、<a target="_blank" rel="noopener" href="https://webkit.org/blog/10247/new-webkit-features-in-safari-13-1/">Safari 13.1+</a> 中下线：</li>
                  <li>FTP 已在 <a target="_blank" rel="noopener" href="https://developer.apple.com/documentation/safari-release-notes/safari-14-beta-release-notes">Safari 14+</a>、<a target="_blank" rel="noopener" href="https://www.chromestatus.com/feature/6246151319715840">Chrome 87+</a> 中下线，将在 <a target="_blank" rel="noopener" href="https://www.ghacks.net/2020/03/19/mozilla-will-remove-ftp-support-in-the-firefox-web-browser/">Firefox 将来版本</a>中下线；</li>
                  <li>Flash 已在 <a target="_blank" rel="noopener" href="https://developer.apple.com/documentation/safari-release-notes/safari-14-beta-release-notes">Safari 14+</a> 中下线，将在 <a target="_blank" rel="noopener" href="https://www.chromium.org/flash-roadmap">Chrome 88+</a>、<a href="hhttps://blog.mozilla.org/futurereleases/2020/11/17/ending-firefox-support-for-flash/#:~:text=On%20January%2026,%202021,%20Firefox,final%20version%20to%20support%20Flash.">Firefox 85+</a> 中下线；</li>
                </ul>
              </li>
              <li>
                <p>跨站隔离优化：</p>
              </li>
              <li>
                <ul>
                  <li>2018 年初，由于 Spectre 漏洞的暴露，高精度定时器和 Shared Memory API 被禁用，为预防相关漏洞，浏览器需要保证不同站点在不同进程，相互隔离；</li>
                  <li>为了保证跨站进程隔离，<code>Cross-Origin-Opener-Policy</code> 和 <code>Cross-Origin-Embedder-Policy</code> 返回头被设计出来。当它们被服务端正确返回时，<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer/Planned_changes">Firefox 79+</a> 和 <a target="_blank" rel="noopener" href="https://web.dev/coop-coep/">Chrome 88+</a> 对 Shared Memory API 的支持将重新打开；</li>
                </ul>
              </li>
              <li>
                <p>跨站嗅探预防：</p>
              </li>
              <li>
                <ul>
                  <li><a target="_blank" rel="noopener" href="https://webkit.org/blog/10247/new-webkit-features-in-safari-13-1/">在 Safari 13.1+ 中</a>，第三方 Cookie 完全被禁用，JavaScript 可写的存储最多保留一周；</li>
                  <li><a target="_blank" rel="noopener" href="https://webkit.org/blog/11340/new-webkit-features-in-safari-14/">在 Safari 14+ 中</a>，跨域资源的 Cookie 完全被禁用，除非经由 Storage Access API 显式获取用户的同意；第三方 CNAME 的域名 Cookie 最多可设置 7 天有效期；</li>
                  <li><a target="_blank" rel="noopener" href="https://blog.mozilla.org/blog/2020/08/04/latest-firefox-rolls-out-enhanced-tracking-protection-2-0-blocking-redirect-trackers-by-default/">在 Firefox 79+ 中</a>，新版智能跨站嗅探预防（ETP 2.0）上线，将每 24 小时清除被判定为跨站嗅探的相关 Cookie 设置；</li>
                </ul>
              </li>
              <li>
                <p>缓存粒度优化：</p>
              </li>
              <li>
                <ul>
                  <li>Chrome 85+，HTTP 缓存<a target="_blank" rel="noopener" href="https://developers.google.com/web/updates/2020/10/http-cache-partitioning">采用更细粒度的键</a>（ETLD+1）；</li>
                  <li>Firefox <a target="_blank" rel="noopener" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1536058">将在 85 后实现同粒度的缓存键</a>；</li>
                  <li>Safari 12.1+ 实现了<a target="_blank" rel="noopener" href="https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/">顶部 window 域名 + URL 的键控制机制</a>；</li>
                  <li>新的缓存机制隔离了 iframe 内外的跨域请求，能有效规避站点访问嗅探、<a target="_blank" rel="noopener" href="https://portswigger.net/daily-swig/new-xs-leak-techniques-reveal-fresh-ways-to-expose-user-information">跨站搜索攻击</a>、跨站访问跟踪等隐私问题；</li>
                </ul>
              </li>
              <li>
                <p>其他安全策略：</p>
              </li>
              <li>
                <ul>
                  <li><a target="_blank" rel="noopener" href="https://developers.google.com/web/updates/2020/05/nic83">Chrome 83+</a> 支持了 <a target="_blank" rel="noopener" href="https://github.com/w3c/webappsec-trusted-types">Trusted Types</a> 以预防基于 DOM 的 XSS；</li>
                  <li><a target="_blank" rel="noopener" href="https://www.chromium.org/updates/same-site">Chrome 80+</a> 全量了 SameSite Cookie 默认值 <code>SameSite=Lax</code>，此举可以提升站点安全性，从源头防御大量的 CSRF 漏洞；</li>
                  <li><a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/76">Firefox 76+</a> 中使用 <code>location.href</code> 或 <code>&lt;meta http equiv=“refresh”&gt;</code> 等方法导航到未知协议的操作将被阻止。</li>
                </ul>
              </li>
            </ul>
            <h2 id="框架和解决方案-框架"><a href="#框架和解决方案-框架" class="headerlink" title="框架和解决方案 框架"></a>框架和解决方案 框架</h2>
            <p>2020年 React 没有什么全新的概念，React Hooks 在社区从广受关注变成了实际落地；大家等待已久的 Vue 3.0 正式发布，在保留自身特色的同时也从 React 中汲取养分。</p>
            <ul>
              <li>
                <p><a target="_blank" rel="noopener" href="https://reactjs.org/blog/2020/10/20/react-v17.html">React 发布了 17 版本</a>，号称一个没有新特性的大版本更新，提供多版本 React 共存的能力；</p>
              </li>
              <li>
                <p>经过持续两年的努力，2600+ 个提交之后，<a target="_blank" rel="noopener" href="https://github.com/vuejs/vue-next/releases/tag/v3.0.0">Vue 3.0 发布了代号 One Piece 的正式版</a>：</p>
              </li>
              <li>
                <ul>
                  <li>重新划分了模块：可以减少近半运行时大小。拆出的一些独立包也可复用在更多场景：AST 转换、自定义渲染器（如小程序）、响应式系统抽离出来独立使用；</li>
                  <li>新的 Composition API：在保留原有基于对象的 API 同时提出的新的 API，以达到类似 React Hooks 式的逻辑重用；</li>
                  <li>性能提升：与 Vue2 相比，打包后文件尺寸 (tree-shaking 时减少了 41%)、初始渲染 (快了 55%)、更新 (快了 133%) 和内存使用 (少了 54%) 方面都有显著的性能提升，模板编译时优化对性能提升有很大贡献 ；</li>
                  <li>更好的 TypeScript 集成：Vue3 由 TypeScript 写成，新的 Composition API 能很好支持 TS 类型推断，官方的 VSCode 扩展 Vetur 支持了模板中的类型检查，Vue3 更是完整支持了 tsx。</li>
                </ul>
              </li>
            </ul>
            <h2 id="Webpack-又有更多对手"><a href="#Webpack-又有更多对手" class="headerlink" title="Webpack 又有更多对手"></a>Webpack 又有更多对手</h2>
            <p>出于对 Webpack 的爱恨交加，大家纷纷用更新颖的想法或更激进的技术造起了全新的开发工具链，也促使 Webpack 加快自我迭代的步伐。</p>
            <ul>
              <li><a target="_blank" rel="noopener" href="https://webpack.js.org/blog/2020-10-10-webpack-5-release/">Webpack 5.0 正式发布</a>，这是时隔 2 年半的大版本更新，通过持久缓存提高构建性能，通过更好的 Tree Shaking 和代码生成来降低打包大小；</li>
              <li><a target="_blank" rel="noopener" href="https://github.com/vuejs/vite">vite</a> 作为 Vue 作者的新项目快速引来关注，它基于浏览器原生 ES imports，因而有更快的冷启动和热更新，整体速度与模块数量无关。没有打包的过程，源码直接传输给浏览器使用原生的 <code>&lt;script module&gt;</code> 语法进行引入，开发服务器拦截请求和对需要转换的代码进行转换，实现了真正的按需编译。生产环境提供了 vite build 脚本进行打包，它基于 <a target="_blank" rel="noopener" href="https://rollupjs.org/">rollup</a> 进行打包；</li>
              <li>基于原生 <a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">ES Module (ESM)</a> 的现代打包工具<a target="_blank" rel="noopener" href="https://www.snowpack.dev/posts/2020-05-26-snowpack-2-0-release/"> Snowpack 2.0 发布</a>，其启动时间不到 50 毫秒，可以在大型项目中保持快速运行，内置对 TypeScript，JSX，CSS Modules 的支持，可与 React，Preact，Vue，Svelte 等前端开发框架结合使用；</li>
              <li>Babel 作者 Sebastian McKenzie 推出了 JavaScript 工具链 <a target="_blank" rel="noopener" href="https://github.com/rome/tools">Rome</a>，包含编译器、代码风格检查、格式化、打包、测试框架等内容，亮点在于零第三方依赖并简化 API 配置。</li>
            </ul>
            <h2 id="致谢"><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2>
            <p>今年是前端快爆的第三年，还是要感谢四位轮值编辑：承虎、一丝、池冰、墨尘，以及特邀编辑：紫云飞。谢谢各位的一路陪伴，字字句句的斟酌，才有了这三年的沉淀。</p>
            <p>当然最需要感谢的还是各位粉丝，谢谢你们一直以来的关注与点赞，给了我们很大的动力。新的一年里，我们将继续秉承：原创、求精、求严的精神，一起前行！</p>
            <h3 id="勘误"><a href="#勘误" class="headerlink" title="勘误"></a>勘误</h3>
            <ul>
              <li>
                <p><a target="_blank" rel="noopener" href="https://www.zhihu.com/people/cfdec6226ece879d2571fbc274372e9f">@尤雨溪</a></p>
                <p>：Rome 已经跟 Facebook 无关，作者 Sebastian McKenzie 之前跳槽去了 Discord，现在已经辞职靠捐赠全职开发 Rome。</p>
              </li>
            </ul>

          </div>





          <footer class="post-footer">
            <div class="post-tags">
              <a href="/tags/JavaScript/" rel="tag"># JavaScript</a>
              <a href="/tags/2020/" rel="tag"># 2020</a>
            </div>



            <div class="post-nav">
              <div class="post-nav-item">
                <a href="/blob/2021-06-08-new-features-of-javsscript-es12-&-es2021/" rel="prev" title="JavsScript ES12&ES2021的新特性">
                  <i class="fa fa-chevron-left"></i> JavsScript ES12&ES2021的新特性
                </a>
              </div>
              <div class="post-nav-item">
                <a href="/blob/2021-06-10-what-are-the-seven-highlights-of-vue3.0/" rel="next" title="Vue3.0 七大亮点是什么">
                  Vue3.0 七大亮点是什么 <i class="fa fa-chevron-right"></i>
                </a>
              </div>
            </div>
          </footer>
        </article>
      </div>







      <script>
        window.addEventListener('tabs:register', () => {
          let {
            activeClass
          } = CONFIG.comments;
          if (CONFIG.comments.storage) {
            activeClass = localStorage.getItem('comments_active') || activeClass;
          }
          if (activeClass) {
            const activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
            if (activeTab) {
              activeTab.click();
            }
          }
        });
        if (CONFIG.comments.storage) {
          window.addEventListener('tabs:click', event => {
            if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
            const commentClass = event.target.classList[1];
            localStorage.setItem('comments_active', commentClass);
          });
        }
      </script>
    </div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


      <div class="copyright">
        &copy;
        <span itemprop="copyrightYear">2021</span>
        <span class="with-love">
          <i class="fa fa-heart"></i>
        </span>
        <span class="author" itemprop="copyrightHolder">holidaypenguin</span>
      </div>
      <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/mist/" class="theme-link" rel="noopener" target="_blank">NexT.Mist</a> 强力驱动
      </div>

    </div>
  </footer>


  <script size="300" alpha="0.1" zIndex="-1" src="https://cdn.jsdelivr.net/npm/ribbon.js@1.0.2/dist/ribbon.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>
  <script src="/js/love.js"></script>

  <script src="/js/development.js"></script>
  <script src="/js/utils.js"></script>
  <script src="/js/motion.js"></script>
  <script src="/js/schemes/muse.js"></script>
  <script src="/js/next-boot.js"></script>


  <script src="/js/local-search.js"></script>









  <script>
    (function() {
      function leancloudSelector(url) {
        url = encodeURI(url);
        return document.getElementById(url).querySelector('.leancloud-visitors-count');
      }

      function addCount(Counter) {
        const visitors = document.querySelector('.leancloud_visitors');
        const url = decodeURI(visitors.id);
        const title = visitors.dataset.flagTitle;

        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({
            url
          })))
          .then(response => response.json())
          .then(({
            results
          }) => {
            if (results.length > 0) {
              const counter = results[0];
              leancloudSelector(url).innerText = counter.time + 1;
              Counter('put', '/classes/Counter/' + counter.objectId, {
                  time: {
                    '__op': 'Increment',
                    'amount': 1
                  }
                })
                .catch(error => {
                  console.error('Failed to save visitor count', error);
                });
            } else {
              Counter('post', '/classes/Counter', {
                  title,
                  url,
                  time: 1
                })
                .then(response => response.json())
                .then(() => {
                  leancloudSelector(url).innerText = 1;
                })
                .catch(error => {
                  console.error('Failed to create', error);
                });
            }
          })
          .catch(error => {
            console.error('LeanCloud Counter Error', error);
          });
      }

      function showTime(Counter) {
        const visitors = document.querySelectorAll('.leancloud_visitors');
        const entries = [...visitors].map(element => {
          return decodeURI(element.id);
        });

        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({
            url: {
              '$in': entries
            }
          })))
          .then(response => response.json())
          .then(({
            results
          }) => {
            for (let url of entries) {
              const target = results.find(item => item.url === url);
              leancloudSelector(url).innerText = target ? target.time : 0;
            }
          })
          .catch(error => {
            console.error('LeanCloud Counter Error', error);
          });
      }

      const {
        app_id,
        app_key,
        server_url
      } = {
        "enable": true,
        "app_id": "povuqNsSqFodlakVIwtEX5kb-gzGzoHsz",
        "app_key": "zXD40RDtDB3DMtpC89k0AK7g",
        "server_url": null,
        "security": false
      };

      function fetchData(api_server) {
        const Counter = (method, url, data) => {
          return fetch(`${api_server}/1.1${url}`, {
            method,
            headers: {
              'X-LC-Id': app_id,
              'X-LC-Key': app_key,
              'Content-Type': 'application/json',
            },
            body: JSON.stringify(data)
          });
        };
        if (CONFIG.page.isPost) {
          if (CONFIG.hostname !== location.hostname) return;
          addCount(Counter);
        } else if (document.querySelectorAll('.post-title-link').length >= 1) {
          showTime(Counter);
        }
      }

      const api_server = app_id.slice(-9) === '-MdYXbMMI' ? `https://${app_id.slice(0, 8).toLowerCase()}.api.lncldglobal.com` : server_url;

      if (api_server) {
        fetchData(api_server);
      } else {
        fetch('https://app-router.leancloud.cn/2/route?appId=' + app_id)
          .then(response => response.json())
          .then(({
            api_server
          }) => {
            fetchData('https://' + api_server);
          });
      }
    })();
  </script>



<script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(n){n.imageLazyLoadSetting.processImages=o;var e=n.imageLazyLoadSetting.isSPA,i=n.imageLazyLoadSetting.preloadRatio||1,r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]"));function o(){e&&(r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")));for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(n.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];t=o,e=function(){r=r.filter(function(t){return o!==t})},n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,e&&e()},t.src!==i&&(n.src=i)}()}o(),n.addEventListener("scroll",function(){var t,e;t=o,e=n,clearTimeout(t.tId),t.tId=setTimeout(function(){t.call(e)},500)})}(this);</script></body>

</html>